****
** Replication File:
**
** "Toward a Theory and Measure of Racial Benevolence"
**
** Edana Beauvais and Adam M. Enders
**
** Published in Political Behavior, 2026
****

set more off

* Set working directory!
cd "/Users/adamenders/Dropbox/Benevolent Racism - Beauvais & Enders/Data & analysis/Final Files"

* Import dataset
import delimited " 2020 U.S. Data.csv"

********************************************************************************

****
** Recode and construct variables
****

* Drop those who didn't pass attention check
drop if attention != 3


* Drop those who didn't spend at lest 5 minutes
drop if durationinseconds < 300


* Gender (female)
gen female = gender - 1
recode female (2=0)


* Education
tab edu

gen college = 0
replace college = 1 if edu > 4 & edu < .


* Race
gen white = 0
replace white = 1 if race_5 == 1

gen black = 0
replace black = 1 if race_3 == 1

drop hispanic
gen hispanic = 0
replace hispanic = 1 if latin == 1


* Age
*gen age = 2020 - yearborn
gen agecat = .
replace agecat = 1 if age < 25
replace agecat = 2 if age > 24 & age < 45
replace agecat = 3 if age > 44 & age < 65
replace agecat = 4 if age >= 65 & age < .


* Household income
gen income = inc
recode income (7=.)

gen incomealt = hhi
recode incomealt (-3105 = .)


* Party identification
drop pid
gen pid = .
replace pid = 1 if piddem == 1
replace pid = 2 if piddem == 2
replace pid = 3 if pidlean == 2
replace pid = 4 if pidlean == 3
replace pid = 5 if pidlean == 1
replace pid = 6 if pidgop == 2
replace pid = 7 if pidgop == 1

gen pidstrength = abs(pid - 4)
	
gen rep = .
replace rep = 0 if pid < 4
replace rep = 1 if pid > 4 & pid < .


* Ideology
gen ideo = leftright
recode ideo (11=.)

gen ideostrength = abs(ideo - 5)

gen conserv = . 
replace conserv = 0 if ideo < 5
replace conserv = 1 if ideo > 5 & ideo < .


* South
gen south = 0
replace south = 1 if region == 4


* Interest in politics
gen interest = (attention * -1) + 6


* Religious attendance
gen attend = (churchatt * -1) + 5


* Participation
foreach v of var campaign_1-campaign_5{ 
	recode `v' (.=0)
	}
	
egen participate = rowtotal(campaign_1-campaign_5)


* Retrospective 2016 vote
gen trump2016 = .
replace trump2016 = 0 if cand2016 == 2
replace trump2016 = . if cand2016 == 3
replace trump2016 = . if cand2016 == 4
replace trump2016 = 1 if cand2016 == 1


* Prospective 2020 vote
gen trump2020 = .
replace trump2020 = 0 if candidate2020 == 2
replace trump2020 = . if candidate2020 == 4
replace trump2020 = 1 if candidate2020 == 1



* Feeling thermometers
gen dempartyft = feel_1
gen reppartyft = feel_5
gen trumpft = feel_3
gen bidenft = feel_8
gen blackft = feel_9
gen whiteft = feel_11



* Spending
foreach v of var spend_aidtopoor-spend_welfare{ 
	recode `v' (3=0) (2=0.5)
	}

factor spend_aidtopoor-spend_welfare, ipf	
alpha spend_aidtopoor-spend_welfare, gen(spending)
alpha spend_aidtopoor spend_welfare spend_crime, gen(spendingALT)
	

* Social dominance orientation
gen sdo1 = (allgroups * -1) + 45
recode sdo1 (0=.)

gen sdo2 = (noequality * -1) + 45
recode sdo2 (0=.)

gen sdo3 = (equalityideal * -1) + 45
recode sdo3 (0=.)

gen sdo4 = (superior * -1) + 45
recode sdo4 (0=.)

factor sdo1-sdo4, ipf
alpha sdo1-sdo4, gen(socialdom)


* Racial resentment
replace rr1 = (rr1 * -1) + 16
replace rr2 = rr2 - 10 /* -10 is just because the responses range from 11 to 15, but should be 1 to 5*/
replace rr3 = rr3 - 10
replace rr4 = (rr4 * -1) + 16 /* -1 is reverse coding so that higher values = more resentful */

alpha rr1-rr4, gen(raceresent)


* Benevolent racism scale
replace affirm = (affirm * -1) + 18 /* * -1 is reverse coding so that higher values = more benev racism */
replace police = (police * -1) + 18
replace language = (language * -1) + 29
replace adopt = (adopt * -1) + 18
replace projects = (projects * -1) + 18
replace segregation = (segregation * -1) + 18
replace busing = (busing * -1) + 18

alpha police adopt projects segregation busing, gen(brscale)

alpha police adopt segregation busing, gen(brscaleALT)


* Donation
gen don_nr = 0
replace don_nr = 1 if donation == 7

gen don_br = 0
replace don_br = 1 if donation == 8

gen don_rr = 0
replace don_rr = 1 if donation == 10


* Affirmative action
replace aa_unfair = (aa_unfair * -1) + 28

replace aa_imposter = (aa_imposter * -1) + 16


* Social distance
sum sd_wdate
sum sd_bdate
sum sd_wneigh
sum sd_bneigh
sum sd_wwork
sum sd_bwork

alpha sd_wdate sd_wneigh sd_wwork, gen(ingroup)
alpha sd_bdate sd_bneigh sd_bwork, gen(outgroup)

gen socialdist = ingroup-outgroup


* White identity
replace whiteid = (whiteid * -1) + 6
replace pride = (pride * -1) + 6
replace common = (common * -1) + 6
replace changelaws = (changelaws * -1) + 6
replace minhire = (minhire * -1) + 13

factor whiteid-minhire, ipf
alpha whiteid-minhire, gen(identity)


* White guilt
replace guilt1 = (guilt1 * -1) + 6
replace guilt2 = (guilt2 * -1) + 6
replace guilt3 = (guilt3 * -1) + 6

factor guilt1-guilt3, ipf
alpha guilt1-guilt3, gen(guilty)

********************************************************************************

****
** Table S5, appendix
****

tab agecat
tab edu
tab white
tab black
tab latin
tab region
tab pid
tab ideo

********************************************************************************

****
** Restrict sample to whites only and save
****

drop if white == 0

saveold "Clean, U.S. Data.dta", version(13) replace

********************************************************************************

****
** Descriptives for Table 3
****

tab police 
di 28.80 + 34.32

tab adopt 
di 19.92 + 23.42

tab projects 
di 24.09 + 24.23

tab segregation 
di 32.03 + 26.92

tab busing
di 32.57 + 29.61
 
********************************************************************************

****
** Estimates for Figure 6 and Table S8
****

mlogit donation brscale raceresent pid ideo college age income female south, base(7)
est store mod3

esttab mod3 using "Donation, US.tex", ///
	cells(b(star fmt(3)) se(par fmt(3))) legend label ///
	varlabels(_cons Constant) stats(r2 N, fmt(3 0 1)) ///
	addnotes(Note: Logit coefficients with standard errors in parentheses)


********************************************************************************

**** 
** Estimates for Table 5
****

foreach v of var brscale raceresent edu age income female south blackft pid ///
	socialdist guilty whiteid spending spend_aidtopoor spend_welfare ///
	spend_crime{ 
	egen `v'STD = std(`v')
}

reg brscaleSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store modMV1

reg raceresentSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store modMV2

esttab modMV1 modMV2 using "MVREG, US.tex", ///
	cells(b(star fmt(3)) se(par fmt(3))) legend label ///
	varlabels(_cons Constant) stats(r2 N, fmt(3 0 1)) ///
	addnotes(Note: Standardized OLS coefficients with standard errors in parentheses)

mvreg brscaleSTD raceresentSTD = eduSTD ageSTD incomeSTD femaleSTD southSTD
	
test [brscaleSTD]eduSTD [raceresentSTD]eduSTD
test [brscaleSTD]ageSTD [raceresentSTD]ageSTD
test [brscaleSTD]incomeSTD [raceresentSTD]incomeSTD
test [brscaleSTD]femaleSTD [raceresentSTD]femaleSTD
test [brscaleSTD]southSTD [raceresentSTD]southSTD

pwcorr brscale raceresent edu age income female south, sig

********************************************************************************

**** 
** Estimates for Table 6 and Table S6
****

reg blackftSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod1

reg socialdistSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod2

reg guiltySTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod3

reg whiteidSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod4

esttab mod1 mod2 mod3 mod4 using "Reg 1, US.tex", ///
	cells(b(star fmt(3)) se(par fmt(3))) legend label ///
	varlabels(_cons Constant) stats(r2 N, fmt(3 0 1)) ///
	addnotes(Note: Standardized OLS coefficients with standard errors in parentheses)

	
********************************************************************************

**** 
** Estimates for Table 9 and Table S7
****

reg spendingSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod5

reg spend_aidtopoorSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod6

reg spend_welfareSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod7

reg spend_crimeSTD brscaleSTD raceresentSTD pidSTD eduSTD ageSTD incomeSTD femaleSTD southSTD
est store mod8


esttab mod5 mod6 mod7 mod8 using "Reg 2, US.tex", ///
	cells(b(star fmt(3)) se(par fmt(3))) legend label ///
	varlabels(_cons Constant) stats(r2 N, fmt(3 0 1)) ///
	addnotes(Note: Standardized OLS coefficients with standard errors in parentheses)

********************************************************************************

**** 
** Results of interaction models discussed in Footnote 5
****

reg blackft brscale guilty raceresent whiteid pid edu age income female south

reg socialdist brscale guilty raceresent whiteid pid edu age income female south

reg spending brscale guilty raceresent whiteid pid edu age income female south

reg spendingALT brscale guilty raceresent whiteid pid edu age income female south
reg spend_aidtopoor brscale guilty raceresent whiteid pid  edu age income female south
reg spend_welfare brscale guilty raceresent whiteid pid edu age income female south
reg spend_crime brscale guilty raceresent whiteid pid edu age income female south


reg blackft c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south

reg socialdist c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south

reg spending c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south
margins, dydx(brscale) at(guilty=(0(0.1)1))
marginsplot

reg spendingALT c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south
reg spend_aidtopoor c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south
reg spend_welfare c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south
reg spend_crime c.brscale##c.guilty c.raceresent##c.whiteid pid edu age income female south

********************************************************************************

**** 
** Acquiescence bias analyses discussed in appendix section S15
****

* Make satisficing measure
egen brscale_sd = rowsd(police adopt projects segregation busing)

gen brscale_sat = .
replace brscale_sat = 0 if brscale_sd == 0 & brscale == 5
replace brscale_sat = 1 if brscale_sd > 0
replace brscale_sat = 1 if brscale_sd == 0 & brscale < 5

tab brscale_sat

* Satisficing on items directly preceding BR
replace aa_1 = aa_1 - 1
replace aa_2 = aa_2 - 1
replace aa_3 = aa_3 - 1
replace aa_4 = aa_4 - 1
replace aa_5 = aa_5 - 1
replace aa_6 = aa_6 - 1
replace aa_7 = aa_7 - 1 

egen affirmact = rowtotal(aa_1 aa_2 aa_3 aa_4 aa_5 aa_6 aa_7)
tab affirmact

gen aa_sat = .
replace aa_sat = 0 if affirmact == 0
replace aa_sat = 1 if affirmact > 0

tab brscale_sat aa_sat

* How much does reliability change?
alpha police adopt projects segregation busing
alpha police adopt projects segregation busing if brscale_sat == 1
alpha police adopt projects segregation busing if brscale_sat == 1 & aa_sat == 1

* How much does dimensionality change?
factor police adopt projects segregation busing, ipf
factor police adopt projects segregation busing if brscale_sat == 1, ipf
factor police adopt projects segregation busing if brscale_sat == 1 & aa_sat == 1, ipf

* Still difference between BR and RR?
ttest brscale = raceresent
ttest brscale = raceresent if brscale_sat == 1
ttest brscale = raceresent if brscale_sat == 1 & aa_sat == 1

* BR and RR still weakly correlated?
pwcorr brscale raceresent, sig
pwcorr brscale raceresent if brscale_sat == 1, sig
pwcorr brscale raceresent if brscale_sat == 1 & aa_sat == 1, sig

* Differences in model results?
mlogit donation brscale raceresent pid ideo college age income female south, base(7)
mlogit donation brscale raceresent pid ideo college age income female south if brscale_sat == 1, base(7)
mlogit donation brscale raceresent pid ideo college age income female south if brscale_sat == 1 & aa_sat == 1, base(7)
est store mod3

********************************************************************************

****
** Estimates for Figure S4, stored in "ANES Compare.csv"
****

foreach v of var dempartyft reppartyft bidenft trumpft whiteft blackft ///
raceresent{ 
	sum `v', meanonly
	gen `v'2 = (`v' - r(min))/(r(max) - r(min)) 
}

mean dempartyft2
mean reppartyft2
mean bidenft2
mean trumpft2
mean whiteft2
mean blackft2
mean raceresent2

**
* Compare to 2020 ANES––retrieve from https://electionstudies.org/data-center/
**

gen bidenft = V201151
replace bidenft = . if V201151 < 0 | V201151 > 100

gen trumpft = V201152
replace trumpft = . if V201152 < 0 | V201152 > 100

gen dempartyft = V201156
replace dempartyft = . if V201156 < 0 | V201156 > 100

gen reppartyft = V201157
replace reppartyft = . if V201157 < 0 | V201157 > 100

gen whiteft = V202482
replace whiteft = . if V202482 < 0 | V202482 > 100

gen blackft = V202480
replace blackft = . if V202480 < 0 | V202480 > 100

gen rr1 = V202300
replace rr1 = . if V202300 < 1
replace rr1 = (rr1 * -1) + 6

gen rr2 = V202301
replace rr2 = . if V202301 < 1

gen rr3 = V202302
replace rr3 = . if V202302 < 1

gen rr4 = V202303
replace rr4 = . if V202303 < 1
replace rr4 = (rr4 * -1) + 6

alpha rr1-rr4, gen(raceresent)


foreach v of var dempartyft reppartyft bidenft trumpft whiteft blackft ///
raceresent{ 
	sum `v', meanonly
	gen `v'2 = (`v' - r(min))/(r(max) - r(min)) 
}

mean dempartyft2
mean reppartyft2
mean bidenft2
mean trumpft2
mean whiteft2
mean blackft2
mean raceresent2
